package com.zoho.model_project.utils;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.zoho.model_project.common.ZohoRecord;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;

import java.io.InputStream;
import java.util.*;

@Slf4j
@Component
public class CrmApiUtil {

    final String crmUrl = "https://www.zohoapis.com.cn/crm/v6/"; // 域名路径
    final String positionUrl = crmUrl + "settings/roles";        // 职位路径
    final String profileUrl = crmUrl + "settings/profiles";      // 角色路径
    final String SUCCESS = "SUCCESS";
    final String ERROR = "error";
    final String noteFields = "?fields=Parent_Id,Owner,Created_Time,Note_Title,Note_Content"; // 备注的字段

    ZohoRecord zohoRecord;

    public CrmApiUtil(ZohoRecord zohoRecord) {
        this.zohoRecord = zohoRecord;
    }
    /*
     *****************************************************           通用方法       *****************************************************
     */

    /**
     * 通用_获取 headMap
     */
    private Map<String, String> getHeadMap(String accessToken) {
        Map<String, String> map = new HashMap<>();
        map.put("Authorization", "Zoho-oauthtoken " + accessToken);
        return map;
    }

    /**
     * 通用_get请求
     */
    private JSONObject getRequest(String accessToken, String url) {
        return HttpUtil.getData(url, getHeadMap(accessToken));
    }

    /**
     * 通用_delete请求
     */
    private JSONObject delRequest(String accessToken, String url) {
        return HttpUtil.delData(url, getHeadMap(accessToken));
    }


    /**
     * 通用_使用分页方式，循环获取全量数据
     *
     * @param accessToken token
     * @param baseUrl     基础url，传入后，会自动拼接分页参数
     * @param arrayName   从接口返回中，获取数据的api名称,比如：data、user
     * @return 数据list
     */
    private List<JSONObject> whileGetDataByPage(String accessToken, String baseUrl, String arrayName) {
        Set<JSONObject> set = new HashSet<>();
        int page = 1;
        boolean flag;
        String failUrl = "";
        do {
            try {
                String url = baseUrl + "&page=" + page + "&per_page=200";
                failUrl = url;
                JSONObject record = getRequest(accessToken, url);
                if (Objects.isNull(record)) {
                    return new ArrayList<>();
                }
                JSONArray data = record.getJSONArray(arrayName);
                set.addAll(data.toJavaList(JSONObject.class));
                flag = record.getJSONObject("info").getBoolean("more_records");
                page++;
            } catch (Exception e) {
                log.error("failUrl = " + failUrl);
                e.printStackTrace();
                flag = false;
            }
        } while (flag);
        return new ArrayList<>(set);
    }

    /**
     * 通用_使用page_token方式，循环获取全量数据
     *
     * @return 数据list
     */
    private List<JSONObject> whileGetDataByPageToken(String baseUrl) {
        Set<JSONObject> set = new HashSet<>();
        boolean flag;
        String pageToken = "";
        String url = baseUrl + "&page=1&per_page=200";
        do {
            try {
                if (StringUtils.isNotBlank(pageToken)) {
                    url = baseUrl + "&per_page=200&page_token=";
                    url += pageToken;
                }
                JSONObject record = getRequest(zohoRecord.getAccessToken(), url);
                if (Objects.isNull(record)) {
                    return new ArrayList<>();
                }
                JSONArray data = record.getJSONArray("data");
                set.addAll(data.toJavaList(JSONObject.class));
                flag = record.getJSONObject("info").getBoolean("more_records");
                pageToken = record.getJSONObject("info").getString("next_page_token");
            } catch (Exception e) {
                e.printStackTrace();
                flag = false;
            }
        } while (flag);

        return new ArrayList<>(set);
    }

    /*
     *****************************************************           module  模块       *****************************************************
     */

    /**
     * 获取 【api_supported = true】 可以访问的所有模块名称
     *
     * @return 模块数据
     */
    public List<String> getAllModuleName() {
        List<String> moduleList = new ArrayList<>();

        // 1 所有模块名称
        JSONObject record = getRequest(zohoRecord.getAccessToken(), crmUrl + "settings/modules");
        if (Objects.nonNull(record)) {
            JSONArray modules = record.getJSONArray("modules");
            if (Objects.nonNull(modules) && modules.size() > 0) {
                for (int i = 0; i < modules.size(); i++) {
                    JSONObject jsonObject = modules.getJSONObject(i);
                    String moduleName = jsonObject.getString("api_name");
                    if (jsonObject.getBoolean("api_supported")                  // 能否通过API访问
                            && jsonObject.getBoolean("global_search_supported") // 可支持全局搜索
                            //&& jsonObject.getBoolean("visible")                 // 可支持配置文件
                            && jsonObject.getBoolean("viewable")                // 用户是否可查看记录
                            && jsonObject.getBoolean("show_as_tab")             // true,不显示子表单的名称
                    ) {
                        moduleList.add(moduleName);
                    }
                }
            }
        }
        return moduleList;
    }

    /*
     *****************************************************           record  数据       *****************************************************
     */

    /**
     * record_查询模块的全量数据
     *
     * @param moduleName 模块名称
     * @param fieldList  要查询的字段，id默认查出
     * @return 模块数据集合
     */
    public List<JSONObject> getModuleData(String moduleName, List<String> fieldList) {
        Set<JSONObject> set = new HashSet<>();
        boolean flag;
        String pageToken = "";
        String url = crmUrl + moduleName;
        StringBuilder str = new StringBuilder(url);
        str.append("?");
        for (int i = 0; i < fieldList.size(); i++) {
            if (i == 0) {
                str.append("fields=");
            }
            str.append(fieldList.get(i));
            if (i != fieldList.size() - 1) {
                str.append(",");
            }
        }
        String baseUrl = str.toString();
        url = baseUrl + "&page=1&per_page=200";
        do {
            try {
                if (StringUtils.isNotBlank(pageToken)) {
                    url = baseUrl + "&per_page=200&page_token=";
                    url += pageToken;
                }
                JSONObject record = getRequest(zohoRecord.getAccessToken(), url);
                if (Objects.isNull(record)) {
                    return new ArrayList<>();
                }
                JSONArray data = record.getJSONArray("data");
                set.addAll(data.toJavaList(JSONObject.class));
                flag = record.getJSONObject("info").getBoolean("more_records");
                pageToken = record.getJSONObject("info").getString("next_page_token");
            } catch (Exception e) {
                e.printStackTrace();
                flag = false;
            }
        } while (flag);

        return new ArrayList<>(set);
    }

    /**
     * record_按照搜索条件，返回模块的所有数据，指定要查询的字段
     *
     * @param url 请求地址
     *            String searchUrl = "((Xiangmu.name:equals:" + projectName + ")and(Mobile:equals:" + phone + "))&sort_order=desc&sort_by=Created_Time";
     * @return 模块数据集合
     */
    public List<JSONObject> getModuleDataBySearch(String url) {
        return whileGetDataByPage(zohoRecord.getAccessToken(), url, "data");
    }

    /**
     * record_批量新增数据
     *
     * @param insertList 新增数据
     * @param moduleName 模块名称
     */
    public void batchInsertDataByList(List<JSONObject> insertList, String moduleName) {
        JSONArray insertArray = new JSONArray();
        int num = 100;
        for (int i = 1; i <= insertList.size(); i++) {
            insertArray.add(insertList.get(i - 1));
            /*
             * 1、(moduleData.size() < 100 && i == moduleData.size())，不足100条并且遍历到最后一条时
             * 2、i % 100 == 0，每积攒100条就批量更新
             * 3、((moduleData.size() - i) < 100 && (i == moduleData.size()))，超过100条并且是遍历到最后一条时
             */
            if ((insertList.size() < num && i == insertList.size()) ||
                    i % num == 0 ||
                    ((insertList.size() - i) < num && (i == insertList.size()))) {
                batchInsertData(insertArray, moduleName);
                insertArray = new JSONArray();
            }
        }
    }

    /**
     * 批量新增数据，单次100条
     */
    private void batchInsertData(JSONArray jsonData, String moduleName) {
        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("data", jsonData);

        List<String> list = new ArrayList<>();
        list.add("approval");
        list.add("workflow");
        list.add("blueprint");
        paramsMap.put("trigger", list);
        String url = crmUrl + moduleName;
        try {
            JSONObject jsonObject = HttpUtil.postDataByHead(zohoRecord.getAccessToken(), url, JSONObject.toJSONString(paramsMap));
            if (jsonObject.toJSONString().contains("error")) {
                log.error("数据新增失败parameter={}", jsonData.toJSONString());
                log.error("数据新增失败result={}", jsonObject.toJSONString());
            }
        } catch (Exception e) {
            log.error("数据新增失败parameter={}", JSONObject.toJSONString(jsonData));
            log.error("数据新增失败result_exception={} ", e.getMessage());
        }
    }

    /**
     * record_批量修改数据
     *
     * @param updateList 修改数据
     * @param moduleName 模块名称
     */
    public void batchUpdateDataByList(List<JSONObject> updateList, String moduleName) {
        JSONArray updateArray = new JSONArray();
        int num = 100;
        for (int i = 1; i <= updateList.size(); i++) {
            updateArray.add(updateList.get(i - 1));
            /*
             * 1、(moduleData.size() < 100 && i == moduleData.size())，不足100条并且遍历到最后一条时
             * 2、i % 100 == 0，每积攒100条就批量更新
             * 3、((moduleData.size() - i) < 100 && (i == moduleData.size()))，超过100条并且是遍历到最后一条时
             */
            if ((updateList.size() < num && i == updateList.size()) ||
                    i % num == 0 ||
                    ((updateList.size() - i) < num && (i == updateList.size()))) {
                batchUpdateData(updateArray, moduleName);
                updateArray = new JSONArray();
            }
        }
    }

    /**
     * 批量修改数据，单次200条
     */
    private void batchUpdateData(JSONArray updateData, String moduleName) {
        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("data", updateData);
        String url = crmUrl + moduleName;
        try {
            JSONObject jsonObject = HttpUtil.putData(zohoRecord.getAccessToken(), url, paramsMap);
            if (jsonObject.toJSONString().contains("error")) {
                log.error("数据更新失败parameter={}", updateData.toJSONString());
                log.error("数据更新失败result={}", jsonObject.toJSONString());
            }
        } catch (Exception e) {
            log.error("数据更新失败parameter={}", JSONObject.toJSONString(paramsMap));
            log.error("数据更新失败result_exception={}", e.getMessage());
        }
    }

    /**
     * record_根据id删除CRM模块数据
     */
    public boolean delDataById(String moduleName, String delOrgId) {
        String url = crmUrl + moduleName + "/" + delOrgId;
        JSONObject record = delRequest(zohoRecord.getAccessToken(), url);
        return Objects.nonNull(record) && record.toJSONString().contains(SUCCESS);
    }

    /**
     * record_批量删除CRM模块数据
     *
     * @param moduleName   模块名称
     * @param deleteIdList 要删除的id的集合
     */
    public void batchDeleteModelData(String moduleName, List<String> deleteIdList) {
        String url = crmUrl + moduleName + "?ids=" + String.join(",", deleteIdList);
        delRequest(zohoRecord.getAccessToken(), url);
    }

    /**
     * record_根据id查询模块数据
     *
     * @param moduleName 模块名称
     * @param id         模块id
     * @return 模块数据
     */
    public JSONObject getDataById(String moduleName, String id) {
        String url = crmUrl + moduleName + "/" + id;
        JSONObject record = getRequest(zohoRecord.getAccessToken(), url);
        if (Objects.nonNull(record)) {
            JSONArray data = record.getJSONArray("data");
            if (Objects.nonNull(data)) {
                return data.getJSONObject(0);
            }
        }
        return null;
    }

    /**
     * record_获取某一模块的数据总数
     *
     * @param moduleName 模块名称
     * @return 数据总数
     */
    public int getCount(String moduleName) {
        String url = crmUrl + moduleName + "/actions/count";
        JSONObject record = getRequest(zohoRecord.getAccessToken(), url);
        if (Objects.nonNull(record)) {
            return record.getInteger("count");
        }
        return 0;
    }

    /**
     * record_获取某条数据的时间轴
     *
     * @param moduleName 模块名称
     * @param id         数据id
     * @return 时间轴
     */
    public List<JSONObject> getTimeLine(String moduleName, String id) {
        String baseUrl = crmUrl + moduleName + "/" + id + "/__timeline?sort_by=audited_time";
        return whileGetDataByPage(zohoRecord.getAccessToken(), baseUrl, "__timeline");
    }

    /*
     *****************************************************           COQL    sql执行     *****************************************************
     */

    /**
     * COQLQuery
     *
     * @param selectQuery 执行的sql
     * @return data
     */
    public List<JSONObject> COQLQuery(String selectQuery) {
        String url = crmUrl + "coql";
        Map<String, Object> map = new HashMap<>();
        map.put("select_query", selectQuery);
        try {
            JSONObject jsonObject = HttpUtil.postDataByCOQLQuery(zohoRecord.getAccessToken(), url, map);
            if (Objects.nonNull(jsonObject)) {
                JSONArray data = jsonObject.getJSONArray("data");
                if (Objects.nonNull(data) && data.size() > 0) {
                    return data.toJavaList(JSONObject.class);
                }
            }
        } catch (Exception e) {
            log.error("sql执行出现异常，selectQuery={}", selectQuery);
            log.error("sql执行出现异常，result_exception={}", e.getMessage());
            return new ArrayList<>();
        }
        return new ArrayList<>();
    }

    /*
     *****************************************************           user   用户      *****************************************************
     */

    /**
     * user_获取所有用户数据
     *
     * @return 模块数据
     */
    public List<JSONObject> getAllUserData() {
        String baseUrl = crmUrl + "users?type=AllUsers";
        return whileGetDataByPage(zohoRecord.getAccessToken(), baseUrl, "users");
    }

    /**
     * user_获取所有【活跃】用户数据
     *
     * @return 模块数据
     */
    public List<JSONObject> getAllActiveUserData() {
        String baseUrl = crmUrl + "users?type=ActiveUsers";
        return whileGetDataByPage(zohoRecord.getAccessToken(), baseUrl, "users");
    }



    /**
     * user_获取单个用户数据
     */
    public JSONObject getUserDataById(String id) {
        String url = crmUrl + "users/" + id;
        JSONObject record = getRequest(zohoRecord.getAccessToken(), url);
        if (Objects.nonNull(record)) {
            JSONArray data = record.getJSONArray("users");
            if (Objects.nonNull(data)) {
                return data.getJSONObject(0);
            }
        }
        return null;
    }

    /**
     * user_修改单个用户数据
     */
    public boolean updateUserData(JSONObject userData) {
        List<JSONObject> updateData = new ArrayList<>();
        updateData.add(userData);
        String url = crmUrl + "users";
        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("users", updateData);
        JSONObject record = HttpUtil.putData(zohoRecord.getAccessToken(), url, paramsMap);
        return Objects.nonNull(record) && record.toJSONString().contains(SUCCESS);
    }

    /**
     * user_新增单个用户数据
     */
    public boolean addUserData(JSONObject userData) {
        List<JSONObject> addData = new ArrayList<>();
        addData.add(userData);
        String url = crmUrl + "users";
        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("users", addData);
        JSONObject record = HttpUtil.postDataByHead(zohoRecord.getAccessToken(), url, paramsMap);
        return Objects.nonNull(record) && record.toJSONString().contains(SUCCESS);
    }

    /*
     *****************************************************           position     职位    *****************************************************
     */

    /**
     * position_获取所有职位数据
     *
     * @return 模块数据
     */
    public List<JSONObject> getAllPositionData() {
        JSONObject record = getRequest(zohoRecord.getAccessToken(), positionUrl);
        if (Objects.nonNull(record)) {
            JSONArray data = record.getJSONArray("roles");
            if (Objects.nonNull(data)) {
                return data.toJavaList(JSONObject.class);
            }
        }
        return new ArrayList<>();
    }

    /**
     * position_根据id查询职位
     *
     * @param positionId 职位id
     * @return 模块数据
     */
    public JSONObject getPositionDataById(String positionId) {
        String url = positionUrl + "/" + positionId;
        JSONObject record = getRequest(zohoRecord.getAccessToken(), url);
        if (Objects.nonNull(record)) {
            JSONArray data = record.getJSONArray("roles");
            if (Objects.nonNull(data)) {
                return data.getJSONObject(0);
            }
        }
        return null;
    }

    /**
     * position_新增CRM职位
     *
     * @return 新增职位id
     */
    public String insertPositionData(JSONObject json) {
        List<JSONObject> roleList = new ArrayList<>();
        roleList.add(json);
        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("roles", roleList);
        try {
            JSONObject record = HttpUtil.postDataByHead(zohoRecord.getAccessToken(), positionUrl, paramsMap);
            if (Objects.nonNull(record)) {
                JSONArray data = record.getJSONArray("roles");
                if (Objects.nonNull(data)) {
                    return data.toJavaList(JSONObject.class).get(0).getJSONObject("details").getString("id");
                }
            }
        } catch (Exception e) {
            log.error("新增职位失败parameter={}", json.toJSONString());
            log.error("新增职位失败result_exception={} ", e.getMessage());
        }
        return "";
    }

    /**
     * position_删除CRM职位
     *
     * @param delPositionId 要删除的职位id
     * @param transferId    将要删除的职位下的人员，转移到其他职位的职位id
     * @return 是否删除成功
     */
    public boolean delPositionData(String delPositionId, String transferId) {
        String url = positionUrl + "/" + delPositionId + "?transfer_to_id=" + transferId;
        JSONObject record = delRequest(zohoRecord.getAccessToken(), url);
        return Objects.nonNull(record) && record.toJSONString().contains(SUCCESS);
    }

    /**
     * position_修改CRM职位
     *
     * @return 是否修改成功
     */
    public boolean updateRoleData(JSONObject json) {
        List<JSONObject> roleList = new ArrayList<>();
        roleList.add(json);
        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("roles", roleList);
        JSONObject record = HttpUtil.putData(zohoRecord.getAccessToken(), positionUrl, paramsMap);
        return Objects.nonNull(record) && record.toJSONString().contains(SUCCESS);
    }

    /*
     *****************************************************           role    角色     *****************************************************
     */

    /**
     * role_获取CRM所有角色数据
     *
     * @return 模块数据
     */
    public List<JSONObject> getAllProfilesData() {
        JSONObject record = getRequest(zohoRecord.getAccessToken(), profileUrl);
        if (Objects.nonNull(record)) {
            JSONArray data = record.getJSONArray("profiles");
            if (Objects.nonNull(data)) {
                return data.toJavaList(JSONObject.class);
            }
        }
        return new ArrayList<>();
    }

    /**
     * role_根据id查询角色
     *
     * @param profileId 角色id
     * @return 模块数据
     */
    public JSONObject getProfilesDataById(String profileId) {
        String url = profileUrl + "/" + profileId;
        JSONObject record = getRequest(zohoRecord.getAccessToken(), url);
        if (Objects.nonNull(record)) {
            JSONArray data = record.getJSONArray("profiles");
            if (Objects.nonNull(data)) {
                return data.getJSONObject(0);
            }
        }
        return null;
    }

    /**
     * role_新增CRM角色
     *
     * @return 新增角色id
     */
    public String insertProfilesData(String cloneProfileId, JSONObject json) {
        String url = profileUrl + "/" + cloneProfileId + "/actions/clone";
        List<JSONObject> profilesList = new ArrayList<>();
        profilesList.add(json);
        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("profiles", profilesList);
        JSONObject record = HttpUtil.postDataByHead(zohoRecord.getAccessToken(), url, paramsMap);
        if (Objects.nonNull(record)) {
            JSONArray data = record.getJSONArray("profiles");
            if (Objects.nonNull(data)) {
                return data.toJavaList(JSONObject.class).get(0).getJSONObject("details").getString("id");
            }
        }
        return "";
    }

    /**
     * role_删除CRM角色
     *
     * @param delProfilesId 要删除的角色id
     * @param transferId    将要删除的角色下的人员，转移到其他角色的角色id
     * @return 是否删除成功
     */
    public boolean delProfilesData(String delProfilesId, String transferId) {
        String url = profileUrl + "/" + delProfilesId + "?transfer_to=" + transferId;
        JSONObject record = delRequest(zohoRecord.getAccessToken(), url);
        return Objects.nonNull(record) && record.toJSONString().contains(SUCCESS);
    }

    /**
     * role_修改CRM角色
     *
     * @return 是否修改成功
     */
    public boolean updateProfilesData(String id, JSONObject json) {
        String url = profileUrl + "/" + id;
        List<JSONObject> profilesList = new ArrayList<>();
        profilesList.add(json);
        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("profiles", profilesList);
        JSONObject record = HttpUtil.putData(zohoRecord.getAccessToken(), url, paramsMap);
        return Objects.nonNull(record) && record.toJSONString().contains(SUCCESS);
    }

    /*
     *****************************************************           attachment    附件     *****************************************************
     */

    /**
     * attachment_获取附件数据
     */
    public List<JSONObject> getAttachmentList(String moduleName, String id) {
        Set<JSONObject> set = new HashSet<>();
        String url = crmUrl + moduleName + "/" + id + "/Attachments?fields=id,Owner,File_Name,Created_Time,$link_url";
        JSONObject record = getRequest(zohoRecord.getAccessToken(), url);
        if (Objects.nonNull(record)) {
            JSONArray data = record.getJSONArray("data");
            if (Objects.nonNull(data)) {
                set.addAll(data.toJavaList(JSONObject.class));
            }
        }
        return new ArrayList<>(set);
    }

    /**
     * attachment_上传附件 链接的方式
     *
     * @param moduleName 模块名称
     * @param id         数据id
     * @param title      链接上传后，显示的主题
     * @param link       链接
     */
    public boolean uploadAttachmentByLink(String moduleName, String id, String title, String link) {
        String uploadUrl = crmUrl + moduleName + "/" + id + "/Attachments?attachmentUrl=" + link + "&title=" + title;
        JSONObject jsonObject = HttpUtil.postDataByHead(zohoRecord.getAccessToken(), uploadUrl, new HashMap<>());
        if (Objects.nonNull(jsonObject) && jsonObject.toJSONString().contains(SUCCESS)) {
            return true;
        } else {
            log.error("文件链接上传失败={},模块名称={},id={}", jsonObject.toJSONString(), moduleName, id);
        }
        return false;
    }

    /**
     * attachment_上传附件 文件流的方式
     *
     * @param filePath   文件路径
     * @param moduleName 模块名称
     * @param id         数据id
     */
    public boolean uploadAttachmentByStream(String filePath, String moduleName, String id) {
        String uploadUrl = crmUrl + moduleName + "/" + id + "/Attachments";
        JSONObject jsonObject = HttpUtil.postFileByStream(zohoRecord.getAccessToken(), filePath, uploadUrl);
        if (Objects.nonNull(jsonObject) && jsonObject.toJSONString().contains(SUCCESS)) {
            return true;
        } else {
            log.error("文件流上传失败={},模块名称={},id={}", jsonObject.toJSONString(), moduleName, id);
        }
        return false;
    }

    /**
     * attachment_下载附件,返回文件流
     *
     * @param moduleName   模块名称
     * @param id           数据id
     * @param attachmentId 附件id
     */
    public InputStream downloadAttachment(String moduleName, String id, String attachmentId) {
        String uploadUrl = crmUrl + moduleName + "/" + id + "/Attachments/" + attachmentId;
        return HttpUtil.downloadAttachmentData(uploadUrl, getHeadMap(zohoRecord.getAccessToken()));
    }

    /**
     * attachment_删除附件
     *
     * @param moduleName   模块名称
     * @param id           数据id
     * @param attachmentId 附件id
     */
    public boolean delAttachment(String moduleName, String id, String attachmentId) {
        String uploadUrl = crmUrl + moduleName + "/" + id + "/Attachments/" + attachmentId;
        JSONObject jsonObject = delRequest(zohoRecord.getAccessToken(), uploadUrl);
        if (Objects.nonNull(jsonObject) && jsonObject.toJSONString().contains(SUCCESS)) {
            return true;
        } else {
            log.error("文件删除失败={},模块名称={},id={}", jsonObject.toJSONString(), moduleName, id);
        }
        return false;
    }

    /*
     *****************************************************           Related_Records 相关列表         *****************************************************
     */

    /**
     * Related_Records_查询相关列表数据
     */
    public List<JSONObject> getRelatedRecord(String moduleName, String id, String relatedListApiName) {
        String baseUrl = crmUrl + moduleName + "/" + id + "/" + relatedListApiName;
        return whileGetDataByPage(zohoRecord.getAccessToken(), baseUrl, "data");
    }

    /*
     *****************************************************           Subform 子表单         *****************************************************
     */

    /**
     * SubForm_获取子表单数据
     *
     * @param subFormApiName 子表单api名称
     */
    public List<JSONObject> getSubFormRecord(String subFormApiName, String field) {
        String baseUrl = crmUrl + subFormApiName + "?fields=id,Parent_Id," + field;
        return whileGetDataByPageToken(baseUrl);
    }

    /**
     * SubForm_获取单条子表单数据
     *
     * @param subFormApiName 子表单api名称
     * @param id             子表单中数据id
     */
    public JSONObject getSubFormRecordById(String subFormApiName, String id) {
        String url = crmUrl + subFormApiName + "/" + id;
        JSONObject record = getRequest(zohoRecord.getAccessToken(), url);
        if (Objects.nonNull(record)) {
            JSONArray data = record.getJSONArray("data");
            if (Objects.nonNull(data)) {
                return data.toJavaList(JSONObject.class).get(0);
            }
        }
        return null;
    }

    /*
     *****************************************************           Notes 备注         *****************************************************
     */

    /**
     * Notes_查询 全量 备注
     */
    public List<JSONObject> getAllNotes() {
        String url = crmUrl + "Notes" + noteFields;
        return whileGetDataByPage(zohoRecord.getAccessToken(), url, "data");
    }

    /**
     * Notes_查询 单个 备注
     */
    public JSONObject getNoteById(String noteId) {
        String url = crmUrl + "Notes/" + noteId + noteFields;
        JSONObject record = getRequest(zohoRecord.getAccessToken(), url);
        if (Objects.nonNull(record)) {
            JSONArray data = record.getJSONArray("data");
            if (Objects.nonNull(data)) {
                return data.toJavaList(JSONObject.class).get(0);
            }
        }
        return null;
    }

    /**
     * Notes_查询 某条数据下的所有备注
     *
     * @param moduleName 模块名称
     * @param id         数据id
     */
    public List<JSONObject> getNoteByModuleId(String moduleName, String id) {
        String url = crmUrl + moduleName + "/" + id + "/Notes" + noteFields;
        return whileGetDataByPage(zohoRecord.getAccessToken(), url, "data");
    }

    /**
     * Notes_新增 备注,每次请求，最多新增100条
     *
     * @param moduleName 模块名称
     * @param id         数据id
     * @param title      备注主题
     * @param content    备注内容
     */
    public boolean addNote(String moduleName, String id, String title, String content) {

        List<JSONObject> data = getNoteParameter(title, content);

        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("data", data);

        String url = crmUrl + moduleName + "/" + id + "/Notes";
        JSONObject jsonObject = HttpUtil.postDataByHead(zohoRecord.getAccessToken(), url, JSONObject.toJSONString(paramsMap));
        if (Objects.nonNull(jsonObject) && jsonObject.toJSONString().contains(ERROR)) {
            log.error("新增备注失败={},模块名称={},id={}", jsonObject.toJSONString(), moduleName, id);
            log.error("新增备注失败parameter={}", JSONObject.toJSONString(data));
        } else {
            return true;
        }
        return false;
    }

    /**
     * 获取 备注 的参数
     *
     * @param title   备注标题
     * @param content 备注内容
     */
    private List<JSONObject> getNoteParameter(String title, String content) {
        List<JSONObject> data = new ArrayList<>();
        JSONObject tempJsonObject = new JSONObject();
        tempJsonObject.put("Note_Title", title);
        tempJsonObject.put("Note_Content", content);
        data.add(tempJsonObject);
        return data;
    }

    /**
     * Notes_修改备注
     *
     * @param noteId  备注id
     * @param title   备注标题
     * @param content 备注内容
     */
    public boolean updateNote(String noteId, String title, String content) {

        List<JSONObject> data = getNoteParameter(title, content);

        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("data", data);

        String url = crmUrl + "Notes/" + noteId;
        JSONObject jsonObject = HttpUtil.putData(zohoRecord.getAccessToken(), url, paramsMap);
        if (Objects.nonNull(jsonObject) && jsonObject.toJSONString().contains(SUCCESS)) {
            return true;
        } else {
            log.error("修改备注失败={},id={}", jsonObject.toJSONString(), noteId);
        }
        return false;
    }

    /**
     * Notes_删除备注
     *
     * @param noteId 备注id
     */
    public boolean delNote(String noteId) {
        String url = crmUrl + "Notes/" + noteId;
        JSONObject jsonObject = delRequest(zohoRecord.getAccessToken(), url);
        if (Objects.nonNull(jsonObject) && jsonObject.toJSONString().contains(SUCCESS)) {
            return true;
        } else {
            log.error("备注删除失败={},id={}", jsonObject.toJSONString(), noteId);
        }
        return false;
    }

    /*
     *****************************************************           单独封装的方法         *****************************************************
     */

}
